<!DOCTYPE html>












  


<html class="theme-next pisces use-motion" lang="zh-CN">
<head><meta name="generator" content="Hexo 3.8.0">
  <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
























<link rel="stylesheet" href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2">

<link rel="stylesheet" href="/css/main.css?v=7.1.0">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=7.1.0">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/logo1.jpg?v=7.1.0">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/logo1.jpg?v=7.1.0">


  <link rel="mask-icon" href="/images/logo.svg?v=7.1.0" color="#222">







<script id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Pisces',
    version: '7.1.0',
    sidebar: {"position":"left","display":"post","offset":12,"onmobile":false,"dimmer":false},
    back2top: true,
    back2top_sidebar: false,
    fancybox: false,
    fastclick: false,
    lazyload: false,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>


  




  <meta name="description" content="基于事件驱动状态机的协程框架设计">
<meta name="keywords" content="协程">
<meta property="og:type" content="article">
<meta property="og:title" content="基于事件驱动状态机的协程框架设计">
<meta property="og:url" content="https://luoo.oschina.io/2016/07/30/tech/基于事件驱动状态机的协程框架设计/index.html">
<meta property="og:site_name" content="从你的全世界路过">
<meta property="og:description" content="基于事件驱动状态机的协程框架设计">
<meta property="og:locale" content="zh-CN">
<meta property="og:updated_time" content="2019-04-14T12:28:00.728Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="基于事件驱动状态机的协程框架设计">
<meta name="twitter:description" content="基于事件驱动状态机的协程框架设计">



  <link rel="alternate" href="/atom.xml" title="从你的全世界路过" type="application/atom+xml">



  
  
  <link rel="canonical" href="https://luoo.oschina.io/2016/07/30/tech/基于事件驱动状态机的协程框架设计/">



<script id="page.configurations">
  CONFIG.page = {
    sidebar: "",
  };
</script>

  <title>基于事件驱动状态机的协程框架设计 | 从你的全世界路过</title>
  












  <noscript>
  <style>
  .use-motion .motion-element,
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-title { opacity: initial; }

  .use-motion .logo,
  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-CN">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta">
    

    <div class="custom-logo-site-title">
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">从你的全世界路过</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
    
      
        <p class="site-subtitle">心智渐开，世事渐杂</p>
      
    
    
  </div>

  <div class="site-nav-toggle">
    <button aria-label="切换导航栏">
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>



<nav class="site-nav">
  
    <ul id="menu" class="menu">
      
        
        
        
          
          <li class="menu-item menu-item-home">

    
    
    
      
    

    

    <a href="/" rel="section"><i class="menu-item-icon fa fa-fw fa-home"></i> <br>首页</a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-categories">

    
    
    
      
    

    

    <a href="/categories/" rel="section"><i class="menu-item-icon fa fa-fw fa-th"></i> <br>分类</a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-tags">

    
    
    
      
    

    

    <a href="/tags/" rel="section"><i class="menu-item-icon fa fa-fw fa-tags"></i> <br>标签</a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-archives">

    
    
    
      
    

    

    <a href="/archives/" rel="section"><i class="menu-item-icon fa fa-fw fa-archive"></i> <br>归档</a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-schedule">

    
    
    
      
    

    

    <a href="/schedule/" rel="section"><i class="menu-item-icon fa fa-fw fa-calendar"></i> <br>计划</a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-you">

    
    
    
      
    

    

    <a href="/you/" rel="section"><i class="menu-item-icon fa fa-fw fa-heartbeat"></i> <br>知遇</a>

  </li>
        
        
        
          
          <li class="menu-item menu-item-about">

    
    
    
      
    

    

    <a href="/about/" rel="section"><i class="menu-item-icon fa fa-fw fa-user"></i> <br>关于</a>

  </li>

      
      
    </ul>
  

  

  
</nav>



  



</div>
    </header>

    


    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          
            

          
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://luoo.oschina.io/2016/07/30/tech/基于事件驱动状态机的协程框架设计/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="方林">
      <meta itemprop="description" content="愿你出走半生，归来仍是少年">
      <meta itemprop="image" content="/images/logo1.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="从你的全世界路过">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">基于事件驱动状态机的协程框架设计

              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">

            
            
            

            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              

              
                
              

              <time title="创建时间：2016-07-30 23:29:25" itemprop="dateCreated datePublished" datetime="2016-07-30T23:29:25+08:00">2016-07-30</time>
            

            
          </span>

          
            <span class="post-category">
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/categories/编程技术/" itemprop="url" rel="index"><span itemprop="name">编程技术</span></a></span>

                
                
              
            </span>
          

          
            
            
              
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
            
                <span class="post-meta-item-text">评论数：</span>
                <a href="/2016/07/30/tech/基于事件驱动状态机的协程框架设计/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count valine-comment-count" data-xid="/2016/07/30/tech/基于事件驱动状态机的协程框架设计/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p>基于事件驱动状态机的协程框架设计</p>
<a id="more"></a>
<p>在设计协程之前，先将几个小概念</p>
<h1 id="并发"><a href="#并发" class="headerlink" title="并发"></a><strong>并发</strong></h1><p>最早的计算机，每次只能执行一个程序，只有当当前执行的程序结束后才能执行其它程序，在此期间，别的程序都得等着。到后来，计算机运行速度提高了，程序员们发现，单任务运行一旦陷入IO阻塞状态，CPU就没事做了，很是浪费资源，于是就想要同一时间执行那么三五个程序，几个程序一块跑，于是就有了并发。原理就是将CPU时间分片，分别用来运行多个程序，可以看成是多个独立的逻辑流，由于能快速切换逻辑流，看起来就像是大家一块跑的。<br>并发解决了两个问题：</p>
<ol>
<li>提高了CPU的利用率，在某个程序陷入IO或者其它等待状态时，CPU可以转而执行其它程序。</li>
<li>表面上看起来多个程序一起运行，解决了跑程序排队等待的问题。</li>
</ol>
<p>引入的新问题：<br>并发执行也存在一些问题。我的程序运行到一半，别的进程突然插进来，抢占了CPU，我的中间状态怎么办，我用来存储的内存被覆盖了怎么办？所以跑在一个CPU里面的并发都需要处理上下文切换的问题。进程就是这样抽象出来了一个概念，搭配虚拟内存、进程表之类的东西，用来管理独立运行的程序运行、切换。因为程序的使用涉及到大量的计算机资源配置， 把这活随意的交给用户程序，容易让整个系统被搞挂，资源分配也很难做到相对的公平。所以就出现了操作系统，核心的操作需要陷入内核(kernel)，切换到操作系统，让内核来做。</p>
<h1 id="上下文切换"><a href="#上下文切换" class="headerlink" title="上下文切换"></a><strong>上下文切换</strong></h1><p>上下文切换最早是指进程的上下文切换(context switch)，它发生在内核态。内核调度器会对每个CPU上执行的进程进行调度(scheduling)，以保证每个进程都能分到CPU时间片。当一个进程的时间片用完，或被中断后，内核将保存该进程的运行状态(即上下文)，将其存入运行队列(run queue)，同时让新的进程占用CPU。进程的上下文切换包括内存地址空间、内核态堆栈和硬件上下文(CPU寄存器)的切换，所以代价很高。</p>
<h1 id="线程"><a href="#线程" class="headerlink" title="线程"></a><strong>线程</strong></h1><p>有的时候碰着I/O访问，阻塞了后面所有的计算。空着也是空着，内核就直接把CPU切换到其他进程，让人家先用着。当然除了I\O阻塞，还有时钟阻塞等等。一开始大家都这样弄，后来发现太慢了，一切换进程得反复进入内核，置换掉一大堆状态。进程数一高，大部分系统资源就被进程切换给吃掉了。由于进程切换开销大，所以设计了线程。 大致意思就是，这个地方阻塞了，但我还有其他地方的逻辑流可以计算，这些逻辑流是共享一个地址空间的，不用特别麻烦的重新加载地址空间，页表缓冲区，只要把寄存器刷新一遍就行，能比切换进程开销少点。Linux 2.6内核的clone()系统调用已经支持创建内核级线程，且发布了内核线程库pthread。在同一进程内的线程可以共享进程的地址空间，线程仅需要维护自己的寄存器、栈和线程相关的变量。不过内核线程的调度仍然需要由内核完成，这需要进行用户态和内核态的模式切换，至少包括堆栈和内存映射的切换。而且，不同进程之间的线程切换，有可能会还会导致进程切换，所以代价还是不小。</p>
<h1 id="协程"><a href="#协程" class="headerlink" title="协程"></a><strong>协程</strong></h1><p>为了进一步减小内核态线程上下文切换的开销，于是又有了用户态线程设计，即纤程(Fiber)。如果连时钟阻塞、 线程切换这些功能我们都不需要了，自己在进程里面写一个逻辑流调度的东西。那么我们即可以利用到并发优势，又可以避免反复系统调用，还有进程切换造成的开销，分分钟给你上几千个逻辑流不费力。这就是用户态线程。<br>从上面可以看到，实现一个用户态线程有两个必须要处理的问题：</p>
<ol>
<li>碰着阻塞式I\O会导致整个进程被挂起；</li>
<li>由于缺乏时钟阻塞，进程需要自己拥有调度线程的能力。</li>
</ol>
<p>如果一种实现使得每个线程需要自己通过调用某个方法，主动交出控制权。那么我们就称这种用户态线程是协作式的，即是协程。协程的做法很像早期操作系统的协作式多任务。</p>
<h1 id="协作式多任务"><a href="#协作式多任务" class="headerlink" title="协作式多任务"></a><strong>协作式多任务</strong></h1><p>当任务得一个到了 CPU 时间，除非它自己放弃使用 CPU ，否则将完全霸占 CPU。win3.x就是这个方式。<br>但是，对于操作系统来说，这种做法会让系统不稳定。因为操作系统管理者整个计算机的资源，这个做法容易让系统失去控制（比如用户程序的一个死循环），因此，现在的操作系统都是用的是抢占式多任务。而在一个程序内，使用协作式的方法是可行的，因为自己的程序可以自己控制。<br>可以这么理解：协程就是在用户程序中实现了协作式任务调度。这里输入引用文本进程、线程、协程的设计，都是为了并发任务能够更好的利用CPU资源，协程可以作为进程和线程的有力补充。由于我们可以在用户态调度协程任务，所以，我们可以把一组互相依赖的任务设计成协程。这样，当一个协程任务完成之后，可以手动进行任务调度，把自己挂起(yield)，切换到另外一个协程执行。这样，由于我们可以控制程序主动让出资源，很多情况下将不需要对资源加锁。</p>
<h1 id="并行"><a href="#并行" class="headerlink" title="并行"></a><strong>并行</strong></h1><p>并行的概念是在多核处理器出来之后才有的。当单核CPU的主频遇到瓶颈的时候，设计师们想出了多核CPU来解决处理器性能问题。前面讲到单核的并发可以看出多个独立的逻辑流，那么多核CPU就是真正的多个独立的逻辑流了，多核CPU在一定程度上解决了CPU性能问题。由于有多个独立的中央调度器，真正实现了程序的并行运行，但是也带来一些列问题：1.临界资源的访问（目前大部分采用锁机制解决） 2.数据相关问题（大部分采用原子操作解决） 3.多进程运行资源调度问题。这里不作重点介绍，感兴趣的可以查阅相关资料。</p>
<h1 id="基于事件驱动状态机（EDSM）的协程设计"><a href="#基于事件驱动状态机（EDSM）的协程设计" class="headerlink" title="基于事件驱动状态机（EDSM）的协程设计"></a><strong>基于事件驱动状态机（EDSM）的协程设计</strong></h1><p>协程(coroutine)顾名思义就是“协作的例程”（co-operative routines）。跟具有操作系统概念的线程不一样，协程是在用户空间利用程序语言的语法语义就能实现逻辑上类似多任务的编程技巧。实际上协程的概念比线程还要早，按照 Knuth 的说法“子例程是协程的特例”，一个子例程就是一次子函数调用，那么实际上协程就是类函数一样的程序组件，你可以在一个线程里面轻松创建数十万个协程，就像数十万次函数调用一样。只不过子例程只有一个调用入口起始点，返回之后就结束了，而协程入口既可以是起始点，又可以从上一个返回点继续执行，也就是说协程之间可以通过 yield 方式转移执行权，对称（symmetric）、平级地调用对方，而不是像例程那样上下级调用关系。当然 Knuth 的“特例”指的是协程也可以模拟例程那样实现上下级调用关系，这就叫非对称协程（asymmetric coroutines）。<br>我们举一个例子来看看一种对称协程调用场景，大家最熟悉的“生产者-消费者”事件驱动模型，一个协程负责生产产品并将它们加入队列，另一个负责从队列中取出产品并使用它。为了提高效率，你想一次增加或删除多个产品。伪代码可以是这样的：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"># producer coroutine</span><br><span class="line">loop</span><br><span class="line">while queue is not full</span><br><span class="line">create some new items</span><br><span class="line">add the items to queue</span><br><span class="line">yield to consumer</span><br><span class="line"></span><br><span class="line"># consumer coroutine</span><br><span class="line">loop</span><br><span class="line">while queue is not empty</span><br><span class="line">remove some items from queue</span><br><span class="line">use the items</span><br><span class="line">yield to producer</span><br></pre></td></tr></table></figure>
<p>按照这种模型，我们编写自己的协程框架，首先，我们需要一个设计一个优先队列：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br></pre></td><td class="code"><pre><span class="line">//priority_heap_queue.hpp</span><br><span class="line">///基于堆的优先队列</span><br><span class="line">#include &lt;string&gt;</span><br><span class="line">template &lt;typename T&gt;</span><br><span class="line">class priority_heap_queue</span><br><span class="line">&#123;</span><br><span class="line">    T* heap;</span><br><span class="line"></span><br><span class="line">    void siftup(unsigned int n) </span><br><span class="line">    &#123;</span><br><span class="line">        auto v = heap[n];</span><br><span class="line">        for (auto n2 = n / 2; n &gt; 0 &amp;&amp; v &lt;= heap[n2]; n = n2, n2 /= 2)</span><br><span class="line">        &#123;</span><br><span class="line">            heap[n] = heap[n2];</span><br><span class="line">        &#125;</span><br><span class="line">        heap[n] = v;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    void siftdown(int n)</span><br><span class="line">    &#123;</span><br><span class="line">        auto v = heap[n];</span><br><span class="line">        for (auto n2 = n * 2; n2 &lt; count; n = n2, n2 *= 2)</span><br><span class="line">        &#123;</span><br><span class="line">            if (n2 + 1 &lt; count &amp;&amp; heap[n2 + 1] &lt;= heap[n2]) n2++;</span><br><span class="line">            if (v &lt;= heap[n2]) break;</span><br><span class="line">            heap[n] = heap[n2];</span><br><span class="line">        &#125;</span><br><span class="line">        heap[n] = v;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">public:</span><br><span class="line">    int count;</span><br><span class="line">    int capacity;</span><br><span class="line"></span><br><span class="line">    explicit priority_heap_queue(int cap)</span><br><span class="line">    &#123;</span><br><span class="line">        capacity = cap;</span><br><span class="line">        heap = new T[capacity];</span><br><span class="line">        count = 0;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    ~priority_heap_queue()</span><br><span class="line">    &#123;</span><br><span class="line">        if(heap != nullptr)</span><br><span class="line">        &#123;</span><br><span class="line">            delete[] heap;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    void push(T v)</span><br><span class="line">    &#123;</span><br><span class="line">        if (count &gt;= capacity)</span><br><span class="line">        &#123;</span><br><span class="line">            auto tmp = new T[capacity * 2];</span><br><span class="line">            for (auto i = 0; i &lt; capacity; i++)</span><br><span class="line">            &#123;</span><br><span class="line">                tmp[i] = heap[i];</span><br><span class="line">            &#125;</span><br><span class="line">            capacity *= 2;</span><br><span class="line">            delete heap;</span><br><span class="line">            heap = tmp;</span><br><span class="line">        &#125;</span><br><span class="line">        heap[count] = v;</span><br><span class="line">        siftup(count++);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    T pop()</span><br><span class="line">    &#123;</span><br><span class="line">        auto v = top();</span><br><span class="line">        heap[0] = heap[--count];</span><br><span class="line">        if (count &gt; 1) siftdown(0);</span><br><span class="line">        return v;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    T top()</span><br><span class="line">    &#123;</span><br><span class="line">        return heap[0];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    void clear()</span><br><span class="line">    &#123;</span><br><span class="line">        count = 0;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    bool empty() const</span><br><span class="line">    &#123;</span><br><span class="line">        return count &gt; 0;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    void foreach(void (*callback)(T))</span><br><span class="line">    &#123;</span><br><span class="line">        for(auto i = 0; i &lt; count; i++)</span><br><span class="line">        &#123;</span><br><span class="line">            callback(heap[i]);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    void foreach(void (*callback)(T &amp;, unsigned long), unsigned long tid)</span><br><span class="line">    &#123;</span><br><span class="line">        for (auto i = 0; i &lt; count; i++)</span><br><span class="line">        &#123;</span><br><span class="line">            callback(heap[i], tid);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    void foreach(void(*callback)(T &amp;, std::string), std::string tid)</span><br><span class="line">    &#123;</span><br><span class="line">        for (auto i = 0; i &lt; count; i++)</span><br><span class="line">        &#123;</span><br><span class="line">            callback(heap[i], tid);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>其次，为了实现自行调度的标准，需要设计一个计时器类：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br></pre></td><td class="code"><pre><span class="line">//timer.h</span><br><span class="line"></span><br><span class="line">#pragma once</span><br><span class="line">#include &lt;chrono&gt;</span><br><span class="line"></span><br><span class="line">class timer</span><br><span class="line">&#123;</span><br><span class="line">public:</span><br><span class="line"></span><br><span class="line">    std::chrono::time_point&lt;std::chrono::system_clock&gt; time;</span><br><span class="line"></span><br><span class="line">    timer();</span><br><span class="line"></span><br><span class="line">    ~timer();</span><br><span class="line"></span><br><span class="line">    void reset();</span><br><span class="line"></span><br><span class="line">    std::chrono::milliseconds elapsed() const;</span><br><span class="line"></span><br><span class="line">    //微秒</span><br><span class="line">    std::chrono::microseconds elapsed_micro() const;</span><br><span class="line"></span><br><span class="line">    //纳秒</span><br><span class="line">    std::chrono::nanoseconds elapsed_nano() const;</span><br><span class="line"></span><br><span class="line">    //秒</span><br><span class="line">    std::chrono::seconds elapsed_seconds() const;</span><br><span class="line"></span><br><span class="line">    //分</span><br><span class="line">    std::chrono::minutes elapsed_minutes() const;</span><br><span class="line"></span><br><span class="line">    //时</span><br><span class="line">    std::chrono::hours elapsed_hours() const;</span><br><span class="line"></span><br><span class="line">    bool operator&lt;=(timer &amp;t) const;</span><br><span class="line"></span><br><span class="line">    bool operator&gt;(timer &amp;t) const;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">//timer.cpp</span><br><span class="line"></span><br><span class="line">#include &quot;timer.h&quot;</span><br><span class="line">#include&lt;chrono&gt;</span><br><span class="line">using namespace std;</span><br><span class="line">using namespace chrono;</span><br><span class="line"></span><br><span class="line">timer::timer()</span><br><span class="line">&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">timer::~timer()</span><br><span class="line">&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void timer::reset()</span><br><span class="line">&#123;</span><br><span class="line">    time = system_clock::now();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">milliseconds timer::elapsed() const</span><br><span class="line">&#123;</span><br><span class="line">    return duration_cast&lt;milliseconds&gt;(system_clock::now() - time);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">microseconds timer::elapsed_micro() const</span><br><span class="line">&#123;</span><br><span class="line">    return duration_cast&lt;microseconds&gt;(system_clock::now() - time);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">nanoseconds timer::elapsed_nano() const</span><br><span class="line">&#123;</span><br><span class="line">    return duration_cast&lt;nanoseconds&gt;(system_clock::now() - time);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">seconds timer::elapsed_seconds() const</span><br><span class="line">&#123;</span><br><span class="line">    return duration_cast&lt;seconds&gt;(system_clock::now() - time);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">minutes timer::elapsed_minutes() const</span><br><span class="line">&#123;</span><br><span class="line">    return duration_cast&lt;minutes&gt;(system_clock::now() - time);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">hours timer::elapsed_hours() const</span><br><span class="line">&#123;</span><br><span class="line">    return duration_cast&lt;hours&gt;(system_clock::now() - time);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">bool timer::operator&lt;=(timer&amp; t) const</span><br><span class="line">&#123;</span><br><span class="line">    return time &lt;= t.time;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">bool timer::operator&gt;(timer&amp; t) const</span><br><span class="line">&#123;</span><br><span class="line">    return time &lt; t.time;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>然后，我们需要把每个任务封装成一个对象</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br></pre></td><td class="code"><pre><span class="line">//timer_task.h</span><br><span class="line">#pragma once</span><br><span class="line">#include &quot;timer.h&quot;</span><br><span class="line">#include &lt;memory&gt;</span><br><span class="line">#include &lt;chrono&gt;</span><br><span class="line">#include &lt;string&gt;</span><br><span class="line"></span><br><span class="line">class timer_task</span><br><span class="line">&#123;</span><br><span class="line">public:</span><br><span class="line">    timer_task();</span><br><span class="line"></span><br><span class="line">    timer_task(timer timer, std::shared_ptr&lt;void&gt; userData, std::chrono::seconds offset, void(*callback)(std::shared_ptr&lt;void&gt;), std::string name);</span><br><span class="line"></span><br><span class="line">    ~timer_task();</span><br><span class="line"></span><br><span class="line">    void Destory();</span><br><span class="line"></span><br><span class="line">    void DoTask() const;</span><br><span class="line"></span><br><span class="line">    bool operator&lt;= (timer_task &amp;timer) const;</span><br><span class="line"></span><br><span class="line">    bool operator&gt; (timer_task &amp;timer) const;</span><br><span class="line"></span><br><span class="line">    timer_task &amp;operator=(const timer_task &amp;timer);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    void(*do_task)(std::shared_ptr&lt;void&gt;);</span><br><span class="line"></span><br><span class="line">    unsigned long tid;</span><br><span class="line"></span><br><span class="line">    timer timer;</span><br><span class="line"></span><br><span class="line">    std::shared_ptr&lt;void&gt; user_data;</span><br><span class="line"></span><br><span class="line">    std::chrono::seconds offset;</span><br><span class="line"></span><br><span class="line">    std::string name;</span><br><span class="line"></span><br><span class="line">    bool need_remove;</span><br><span class="line"></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">//timer_task.cpp</span><br><span class="line">#include &quot;timer_task.h&quot;</span><br><span class="line"></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">// ReSharper disable once CppPossiblyUninitializedMember</span><br><span class="line">timer_task::timer_task()</span><br><span class="line">&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// ReSharper disable once CppPossiblyUninitializedMember</span><br><span class="line">timer_task::timer_task(::timer timer, shared_ptr&lt;void&gt; userData, chrono::seconds offset, void(*callback)(std::shared_ptr&lt;void&gt;), string name)</span><br><span class="line">&#123;</span><br><span class="line">    this-&gt;timer = timer;</span><br><span class="line">    this-&gt;offset = offset;</span><br><span class="line">    this-&gt;do_task = callback;</span><br><span class="line">    this-&gt;user_data = userData;</span><br><span class="line">    this-&gt;need_remove = false;</span><br><span class="line">    this-&gt;name = name;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">timer_task::~timer_task()</span><br><span class="line">&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void timer_task::Destory()</span><br><span class="line">&#123;</span><br><span class="line">    need_remove = true;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void timer_task::DoTask() const</span><br><span class="line">&#123;</span><br><span class="line">    do_task(user_data);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">bool timer_task::operator&lt;=(timer_task&amp; timer) const</span><br><span class="line">&#123;</span><br><span class="line">    return this-&gt;timer.time + offset &lt;= timer.timer.time + offset;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">bool timer_task::operator&gt;(timer_task&amp; timer) const</span><br><span class="line">&#123;</span><br><span class="line">    return this-&gt;timer.time + offset &gt; timer.timer.time + offset;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">timer_task &amp;timer_task::operator=(const timer_task&amp; timer)</span><br><span class="line">&#123;</span><br><span class="line">    this-&gt;tid = timer.tid;</span><br><span class="line">    this-&gt;timer = timer.timer;</span><br><span class="line">    this-&gt;offset = timer.offset;</span><br><span class="line">    this-&gt;do_task = timer.do_task;</span><br><span class="line">    this-&gt;user_data = timer.user_data;</span><br><span class="line">    this-&gt;need_remove = false;</span><br><span class="line">    this-&gt;name = timer.name;</span><br><span class="line">    return *this;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>再设计一个任务管理对象，单例模式：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br></pre></td><td class="code"><pre><span class="line">//timer_task_manager.h</span><br><span class="line">#pragma once</span><br><span class="line">#include &quot;timer_task.h&quot;</span><br><span class="line">#include &quot;priority_heap_queue.hpp&quot;</span><br><span class="line"></span><br><span class="line">class timer_task_manager</span><br><span class="line">&#123;</span><br><span class="line">    priority_heap_queue&lt;timer_task&gt; task_queue;</span><br><span class="line"></span><br><span class="line">    static unsigned long number_of_timer_task;</span><br><span class="line"></span><br><span class="line">    static timer_task_manager *instance;</span><br><span class="line"></span><br><span class="line">public:</span><br><span class="line"></span><br><span class="line">    static timer_task_manager* get_instance();</span><br><span class="line"></span><br><span class="line">    void do_timer_task();</span><br><span class="line"></span><br><span class="line">    timer_task_manager();</span><br><span class="line"></span><br><span class="line">    ~timer_task_manager();</span><br><span class="line"></span><br><span class="line">    unsigned long add_timer_task(timer_task t);</span><br><span class="line"></span><br><span class="line">    void remove_timer_task(unsigned long tid);</span><br><span class="line"></span><br><span class="line">    void remove_timer_task(std::string name);</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">//timer_task_manager.cpp</span><br><span class="line"></span><br><span class="line">#include &quot;timer_task_manager.h&quot;</span><br><span class="line">#include &lt;ostream&gt;</span><br><span class="line">#include &lt;iostream&gt;</span><br><span class="line"></span><br><span class="line">timer_task_manager* timer_task_manager::instance = nullptr;</span><br><span class="line">unsigned long timer_task_manager::number_of_timer_task = 0;</span><br><span class="line"></span><br><span class="line">timer_task_manager* timer_task_manager::get_instance()</span><br><span class="line">&#123;</span><br><span class="line">    if(instance == nullptr)</span><br><span class="line">    &#123;</span><br><span class="line">        instance = new timer_task_manager();</span><br><span class="line">    &#125;</span><br><span class="line">    return instance;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void timer_task_manager::do_timer_task()</span><br><span class="line">&#123;</span><br><span class="line">    while(task_queue.count &gt; 0)</span><br><span class="line">    &#123;</span><br><span class="line">        auto task = task_queue.top();</span><br><span class="line">        if(task.timer.elapsed_seconds() &gt;= task.offset)</span><br><span class="line">        &#123;</span><br><span class="line">            if(!task.need_remove)</span><br><span class="line">            &#123;</span><br><span class="line">                task.DoTask();</span><br><span class="line">            &#125;</span><br><span class="line">            task_queue.pop();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">timer_task_manager::timer_task_manager():task_queue(10)</span><br><span class="line">&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">timer_task_manager::~timer_task_manager()</span><br><span class="line">&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">unsigned long timer_task_manager::add_timer_task(timer_task t)</span><br><span class="line">&#123;</span><br><span class="line">    t.tid = number_of_timer_task++;</span><br><span class="line">    task_queue.push(t);</span><br><span class="line">    return t.tid;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void timer_task_manager::remove_timer_task(unsigned long tid)</span><br><span class="line">&#123;</span><br><span class="line">    auto remove = [](timer_task &amp;t, unsigned long Tid) &#123; if (t.tid == Tid) t.need_remove = true; &#125;;</span><br><span class="line">    task_queue.foreach(remove, tid);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void timer_task_manager::remove_timer_task(std::string name)</span><br><span class="line">&#123;</span><br><span class="line">    auto remove = [](timer_task &amp;t, std::string Name) &#123; if (t.name.compare(Name) == 0) t.need_remove = true; &#125;;</span><br><span class="line">    task_queue.foreach(remove, name);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>最后，任务调度器：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br></pre></td><td class="code"><pre><span class="line">//tick_processer.h</span><br><span class="line">#pragma once</span><br><span class="line">#include &lt;chrono&gt;</span><br><span class="line"></span><br><span class="line">class tick_processer</span><br><span class="line">&#123;</span><br><span class="line">    std::chrono::time_point&lt;std::chrono::system_clock&gt; last_tick_time;</span><br><span class="line"></span><br><span class="line">    std::chrono::time_point&lt;std::chrono::system_clock&gt; begin;</span><br><span class="line"></span><br><span class="line">public:</span><br><span class="line"></span><br><span class="line">    tick_processer();</span><br><span class="line"></span><br><span class="line">    virtual ~tick_processer();</span><br><span class="line">    </span><br><span class="line">    void run(std::chrono::milliseconds tick_millisecond);</span><br><span class="line"></span><br><span class="line">    virtual void init();</span><br><span class="line"></span><br><span class="line">    std::chrono::milliseconds one_loop();</span><br><span class="line"></span><br><span class="line">    virtual void one_tick(std::chrono::milliseconds delts, std::chrono::milliseconds ms);</span><br><span class="line"></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">//tick_processer.cpp</span><br><span class="line">#include &lt;thread&gt;</span><br><span class="line">#include &lt;iostream&gt;</span><br><span class="line">#include &quot;tick_processer.h&quot;</span><br><span class="line">#include &quot;timer_task_manager.h&quot;</span><br><span class="line">using namespace std;</span><br><span class="line">using namespace chrono;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">// ReSharper disable once CppPossiblyUninitializedMember</span><br><span class="line">tick_processer::tick_processer()</span><br><span class="line">&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">tick_processer::~tick_processer()</span><br><span class="line">&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void tick_processer::run(milliseconds tick_millisecond)</span><br><span class="line">&#123;</span><br><span class="line">    init();</span><br><span class="line">    while(true)</span><br><span class="line">    &#123;</span><br><span class="line">        auto process_time = one_loop();</span><br><span class="line">        if(process_time &lt; tick_millisecond)</span><br><span class="line">        &#123;</span><br><span class="line">            this_thread::sleep_for(milliseconds(tick_millisecond - process_time));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void tick_processer::init()</span><br><span class="line">&#123;</span><br><span class="line">    last_tick_time = system_clock::now();</span><br><span class="line">    begin = last_tick_time;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">milliseconds tick_processer::one_loop()</span><br><span class="line">&#123;</span><br><span class="line">    auto tick_start_time = system_clock::now();</span><br><span class="line">    auto delts = duration_cast&lt;milliseconds&gt;(tick_start_time - last_tick_time);</span><br><span class="line">    auto ms = duration_cast&lt;milliseconds&gt;(tick_start_time - begin);</span><br><span class="line">    one_tick(delts, ms);</span><br><span class="line">    last_tick_time = tick_start_time;</span><br><span class="line">    auto tick_end_time = system_clock::now();</span><br><span class="line">    return duration_cast&lt;milliseconds&gt;(tick_end_time - tick_start_time);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void tick_processer::one_tick(milliseconds delts, milliseconds ms)</span><br><span class="line">&#123;</span><br><span class="line">    timer_task_manager::get_instance()-&gt;do_timer_task();</span><br><span class="line">    //所有的逻辑可以从这个地方重写实现</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>一个简单的协程框架就好了，接下来为了配合协程调度，我们设计一个简单的有限状态机</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><span class="line">//base_fsm.h</span><br><span class="line">#pragma once</span><br><span class="line">#include &lt;chrono&gt;</span><br><span class="line"></span><br><span class="line">enum state_set</span><br><span class="line">&#123;</span><br><span class="line">    state0 = 0,</span><br><span class="line">    state1 = 1,</span><br><span class="line">    state2 = 2,</span><br><span class="line">    state3 = 3,</span><br><span class="line">    state4 = 4</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">class base_fsm</span><br><span class="line">&#123;</span><br><span class="line">public:</span><br><span class="line">    std::chrono::microseconds time_in_current_state;</span><br><span class="line">    state_set current_state;</span><br><span class="line"></span><br><span class="line">    base_fsm();</span><br><span class="line">    virtual ~base_fsm();</span><br><span class="line"></span><br><span class="line">    virtual void begin_state(state_set state);</span><br><span class="line">    virtual void update_state(state_set state);</span><br><span class="line">    virtual void end_state(state_set state);</span><br><span class="line"></span><br><span class="line">    void set_state(state_set state);</span><br><span class="line">    void update_fsm(std::chrono::milliseconds delts);</span><br><span class="line"></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">//base_fsm.cpp</span><br><span class="line">#include &quot;base_fsm.h&quot;</span><br><span class="line"></span><br><span class="line">base_fsm::base_fsm():time_in_current_state(0),current_state(state1)</span><br><span class="line">&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">base_fsm::~base_fsm()</span><br><span class="line">&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void base_fsm::begin_state(state_set state)</span><br><span class="line">&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void base_fsm::update_state(state_set state)</span><br><span class="line">&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void base_fsm::end_state(state_set state)</span><br><span class="line">&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void base_fsm::set_state(state_set state)</span><br><span class="line">&#123;</span><br><span class="line">    end_state(current_state);</span><br><span class="line">    current_state = state;</span><br><span class="line">    time_in_current_state = std::chrono::microseconds(0);</span><br><span class="line">    begin_state(current_state);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void base_fsm::update_fsm(std::chrono::milliseconds delts)</span><br><span class="line">&#123;</span><br><span class="line">    if(current_state != state0)</span><br><span class="line">    &#123;</span><br><span class="line">        time_in_current_state += delts;</span><br><span class="line">        update_state(current_state);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>下面是一个简单调用示例：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line">//main.cpp</span><br><span class="line">#pragma once</span><br><span class="line">#include &lt;iostream&gt;</span><br><span class="line">#include &quot;timer_task.h&quot;</span><br><span class="line">#include &quot;base_fsm.h&quot;</span><br><span class="line">#include &lt;string&gt;</span><br><span class="line">#include &quot;tick_processer.h&quot;</span><br><span class="line">#include &quot;timer_task_manager.h&quot;</span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">class my_fsm : public base_fsm</span><br><span class="line">&#123;</span><br><span class="line">public:</span><br><span class="line"></span><br><span class="line">    void begin_state(state_set state) override </span><br><span class="line">    &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    void end_state(state_set state) override </span><br><span class="line">    &#123;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    void update_state(state_set state) override </span><br><span class="line">    &#123;</span><br><span class="line">        auto callback = [](shared_ptr&lt;void&gt; data)</span><br><span class="line">        &#123;</span><br><span class="line">            cout &lt;&lt; *static_pointer_cast&lt;string&gt;(data) &lt;&lt; endl;</span><br><span class="line">        &#125;;</span><br><span class="line">        auto t = timer_task(timer(), shared_ptr&lt;void&gt;(new string(to_string(state))), chrono::seconds(0), callback, &quot;auto&quot;);</span><br><span class="line">        auto tid = timer_task_manager::get_instance()-&gt;add_timer_task(t);</span><br><span class="line"></span><br><span class="line">        switch (state)</span><br><span class="line">        &#123;</span><br><span class="line">        case state1:</span><br><span class="line">            set_state(state2);</span><br><span class="line">            timer_task_manager::get_instance()-&gt;remove_timer_task(tid);</span><br><span class="line">            break;</span><br><span class="line">        case state2:</span><br><span class="line">            set_state(state3);</span><br><span class="line">            timer_task_manager::get_instance()-&gt;remove_timer_task(&quot;auto&quot;);</span><br><span class="line">            break;</span><br><span class="line">        case state3:</span><br><span class="line">            set_state(state4);</span><br><span class="line">            break;</span><br><span class="line">        case state4:</span><br><span class="line">            set_state(state1);</span><br><span class="line">            break;</span><br><span class="line">        case state0: </span><br><span class="line">            break;</span><br><span class="line">        default: </span><br><span class="line">            break;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">class my_processer : public tick_processer</span><br><span class="line">&#123;</span><br><span class="line">public:</span><br><span class="line"></span><br><span class="line">    my_fsm fsm;</span><br><span class="line"></span><br><span class="line">    void init() override </span><br><span class="line">    &#123;</span><br><span class="line">        tick_processer::init();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    void one_tick(chrono::milliseconds delts, chrono::milliseconds ms) override </span><br><span class="line">    &#123;</span><br><span class="line">        tick_processer::one_tick(delts, ms);</span><br><span class="line">        fsm.update_fsm(delts);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">&#123;</span><br><span class="line">    my_processer processer;</span><br><span class="line">    processer.run(std::chrono::milliseconds(200));</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这里，以200ms作为心跳时间，状态机从1到4轮转切换，每个切换的大循环中，状态1和状态2的任务被移除，所以程序会循环输出3和4。<br>在一些更高级的语言中，譬如C#、java等，在编译器层支持了yield语义，借此实现Coroutine框架会更方便快捷。然而这个yield语义是如何实现的呢？<br>我们知道 python 的 yield 语义功能类似于一种迭代生成器，函数会保留上次的调用状态，并&gt; 这里输入引用文本在下次调用时会从上个返回点继续执行。用 C 语言来写就像这样：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">int function(void) &#123;</span><br><span class="line">    int i;</span><br><span class="line">    for (i = 0; i &lt; 10; i++)</span><br><span class="line">         return i; /* won&apos;t work, but wouldn&apos;t it be nice */</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>连续对它调用 10 次，它能分别返回 0 到 9。该怎样实现呢？可以利用 goto 语句，如果我们在函数中加入一个状态变量，就可以这样实现：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">int function(void) &#123;</span><br><span class="line">    static int i, state = 0;</span><br><span class="line">    switch (state) &#123;</span><br><span class="line">         case 0: goto LABEL0;</span><br><span class="line">               case 1: goto LABEL1;</span><br><span class="line">          &#125;</span><br><span class="line">LABEL0:/* start of function */</span><br><span class="line">          for (i = 0; i &lt; 10; i++) &#123;</span><br><span class="line">               state = 1;/* so we will come back to LABEL1 */</span><br><span class="line">               return i;</span><br><span class="line">LABEL1:;/* resume control straight after the return */</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这个方法是可行的。我们在所有需要 yield 的位置都加上标签：起始位置加一个，还有所有 return 语句之后都加一个。每个标签用数字编号，我们在状态变量中保存这个编号，这样就能在我们下次调用时告诉我们应该跳到哪个标签上。每次返回前，更新状态变量，指向到正确的标签；不论调用多少次，针对状态变量的 switch 语句都能找到我们要跳转到的位置。<br>但这还是难看得很。最糟糕的部分是所有的标签都需要手工维护，还必须保证函数中的标签和开头 switch 语句中的一致。每次新增一个 return 语句，就必须想一个新的标签名并将其加到 switch 语句中；每次删除 return 语句时，同样也必须删除对应的标签。这使得维护代码的工作量增加了一倍。<br>仔细想想，其实我们可以不用 switch 语句来决定要跳转到哪里去执行，而是直接利用 switch 语句本身来实现跳转：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">int function(void) &#123;</span><br><span class="line">     static int i, state = 0;</span><br><span class="line">     switch (state) &#123;</span><br><span class="line">          case 0:/* start of function */</span><br><span class="line">          for (i = 0; i &lt; 10; i++) &#123;</span><br><span class="line">               state = 1;/* so we will come back to &quot;case 1&quot; */</span><br><span class="line">               return i;</span><br><span class="line">               case 1:;/* resume control straight after the return */</span><br><span class="line">          &#125;</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>没想到 switch-case 语句可以这样用，其实说白了 C 语言就是脱胎于汇编语言的，switch-case 跟 if-else 一样，无非就是汇编的条件跳转指令的另类实现而已。我们还可以用 <strong>LINE</strong> 宏使其更加一般化：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">int function(void) &#123;</span><br><span class="line">     static int i, state = 0;</span><br><span class="line">     switch (state) &#123;</span><br><span class="line">          case 0:/* start of function */</span><br><span class="line">               for (i = 0; i &lt; 10; i++) &#123;</span><br><span class="line">                    state = __LINE__ + 2;/* so we will come back to &quot;case __LINE__&quot; */</span><br><span class="line">                    return i;</span><br><span class="line">                    case __LINE__:;/* resume control straight after the return */</span><br><span class="line">               &#125;</span><br><span class="line">     &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这样一来我们可以用宏提炼出一种范式，封装成组件：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">#define Begin() static int state=0; switch(state) &#123; case 0:</span><br><span class="line">#define Yield(x) do &#123; state=__LINE__; return x; case __LINE__:; &#125; while (0)</span><br><span class="line">#define End() &#125;</span><br><span class="line">int function(void) &#123;</span><br><span class="line">     static int i;</span><br><span class="line">     Begin();</span><br><span class="line">     for (i = 0; i &lt; 10; i++)</span><br><span class="line">          Yield(i);</span><br><span class="line">     End();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>怎么样，看起来像不像发明了一种全新的语言？实际上我们利用了 switch-case 的分支跳转特性，以及预编译的 __LINE__ 宏，实现了一种隐式状态机，最终实现了“yield 语义”。<br>值得一提的是，这种协程实现方法有个使用上的局限，就是协程调度状态的保存依赖于 static 变量，而不是堆栈上的局部变量，实际上也无法用局部变量（堆栈）来保存状态，这就使得代码不具备可重入性和多线程应用。后来作者补充了一种技巧，就是将局部变量包装成函数参数传入的一个虚构的上下文结构体指针，然后用动态分配的堆来“模拟”堆栈，解决了线程可重入问题。但这样一来反而有损代码清晰，比如所有局部变量都要写成对象成员的引用方式，特别是局部变量很多的时候很麻烦，再比如宏定义 malloc/free 的玩法过于托大，不易控制。<br>我们用ILSpy去观察C#中关于yield return的实现，就会发现，其实C#中的yield语义实现跟上面的方式原理上几乎是一样的，只是它单独把每个带有yield return的函数封转成了一个类型实例，用实例里面的一个成员变量代替上面的static状态变量。上面实现方法，其实代码挺猥琐的，而这些实现了yield return的语言，只是把这些猥琐的事交给编译器干了。</p>
<h1 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a><strong>参考文献</strong></h1><ol>
<li><a href="http://bbs.linuxtone.org/archiver/?tid-21967.html" target="_blank" rel="noopener">http://bbs.linuxtone.org/archiver/?tid-21967.html</a></li>
<li><a href="https://yq.aliyun.com/articles/53673" target="_blank" rel="noopener">https://yq.aliyun.com/articles/53673</a></li>
<li><a href="https://segmentfault.com/a/1190000001813992" target="_blank" rel="noopener">https://segmentfault.com/a/1190000001813992</a></li>
<li><a href="http://www.kuqin.com/shuoit/20140128/337902.html" target="_blank" rel="noopener">http://www.kuqin.com/shuoit/20140128/337902.html</a></li>
<li><a href="http://www.kuqin.com/shuoit/20141013/342602.html" target="_blank" rel="noopener">http://www.kuqin.com/shuoit/20141013/342602.html</a></li>
</ol>

      
    </div>

    

    
    
    

    

    
      
    
    

    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/协程/" rel="tag"># 协程</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2015/09/23/jottings/螃蟹/" rel="next" title="螃蟹">
                <i class="fa fa-chevron-left"></i> 螃蟹
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2016/07/31/tech/漫谈C++为什么不支持模板虚函数/" rel="prev" title="漫谈C++为什么不支持模板虚函数">
                漫谈C++为什么不支持模板虚函数 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>


  </div>


          </div>
          

  
    <div class="comments" id="comments">
    </div>

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image" src="/images/logo1.jpg" alt="方林">
            
              <p class="site-author-name" itemprop="name">方林</p>
              <div class="site-description motion-element" itemprop="description">愿你出走半生，归来仍是少年</div>
          </div>

          
            <nav class="site-state motion-element">
              
                <div class="site-state-item site-state-posts">
                
                  <a href="/archives/">
                
                    <span class="site-state-item-count">27</span>
                    <span class="site-state-item-name">日志</span>
                  </a>
                </div>
              

              
                
                
                <div class="site-state-item site-state-categories">
                  
                    
                      <a href="/categories/">
                    
                  
                    
                    
                      
                    
                      
                    
                      
                    
                    <span class="site-state-item-count">3</span>
                    <span class="site-state-item-name">分类</span>
                  </a>
                </div>
              

              
                
                
                <div class="site-state-item site-state-tags">
                  
                    
                      <a href="/tags/">
                    
                  
                    
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                    <span class="site-state-item-count">17</span>
                    <span class="site-state-item-name">标签</span>
                  </a>
                </div>
              
            </nav>
          

          
            <div class="feed-link motion-element">
              <a href="/atom.xml" rel="alternate">
                <i class="fa fa-rss"></i>
                RSS
              </a>
            </div>
          

          

          
            <div class="links-of-author motion-element">
              
                <span class="links-of-author-item">
                  
                  
                    
                  
                  
                    
                  
                  <a href="https://github.com/yourname" title="GitHub &rarr; https://github.com/yourname" rel="noopener" target="_blank"><i class="fa fa-fw fa-github"></i>GitHub</a>
                </span>
              
                <span class="links-of-author-item">
                  
                  
                    
                  
                  
                    
                  
                  <a href="mailto:sean_ps@163.com" title="E-Mail &rarr; mailto:sean_ps@163.com" rel="noopener" target="_blank"><i class="fa fa-fw fa-envelope"></i>E-Mail</a>
                </span>
              
            </div>
          

          

          
          
            <div class="links-of-blogroll motion-element links-of-blogroll-block">
              <div class="links-of-blogroll-title">
                <i class="fa  fa-fw fa-link"></i>
                Links
              </div>
              <ul class="links-of-blogroll-list">
                
                  <li class="links-of-blogroll-item">
                    <a href="http://www.luoo.net" title="http://www.luoo.net" rel="noopener" target="_blank">落网</a>
                  </li>
                
              </ul>
            </div>
          

          
            
          
          

        </div>
      </div>

      
      <!--noindex-->
        <div class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
            
            
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#并发"><span class="nav-number">1.</span> <span class="nav-text">并发</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#上下文切换"><span class="nav-number">2.</span> <span class="nav-text">上下文切换</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#线程"><span class="nav-number">3.</span> <span class="nav-text">线程</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#协程"><span class="nav-number">4.</span> <span class="nav-text">协程</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#协作式多任务"><span class="nav-number">5.</span> <span class="nav-text">协作式多任务</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#并行"><span class="nav-number">6.</span> <span class="nav-text">并行</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#基于事件驱动状态机（EDSM）的协程设计"><span class="nav-number">7.</span> <span class="nav-text">基于事件驱动状态机（EDSM）的协程设计</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#参考文献"><span class="nav-number">8.</span> <span class="nav-text">参考文献</span></a></li></ol></div>
            

          </div>
        </div>
      <!--/noindex-->
      

      

    </div>
  </aside>
  


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2019</span>
  <span class="with-love" id="animate">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">fanglin</span>

  

  
</div>









        








        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

    

    
  </div>

  

<script>
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>


























  
  <script src="/lib/jquery/index.js?v=2.1.3"></script>

  
  <script src="/lib/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>


  


  <script src="/js/utils.js?v=7.1.0"></script>

  <script src="/js/motion.js?v=7.1.0"></script>



  
  


  <script src="/js/affix.js?v=7.1.0"></script>

  <script src="/js/schemes/pisces.js?v=7.1.0"></script>



  
  <script src="/js/scrollspy.js?v=7.1.0"></script>
<script src="/js/post-details.js?v=7.1.0"></script>



  


  <script src="/js/next-boot.js?v=7.1.0"></script>


  

  

  

  
  

<script src="//cdn1.lncld.net/static/js/3.11.1/av-min.js"></script>



<script src="//unpkg.com/valine/dist/Valine.min.js"></script>

<script>
  var GUEST = ['nick', 'mail', 'link'];
  var guest = 'nick,mail,link';
  guest = guest.split(',').filter(function(item) {
    return GUEST.indexOf(item) > -1;
  });
  new Valine({
    el: '#comments',
    verify: true,
    notify: false,
    appId: 'jjdDCzDO6jlN5yOgAbnVwdJ3-gzGzoHsz',
    appKey: 'jnjP7aorboCG7pJV6HvdMP15',
    placeholder: 'ヾﾉ≧∀≦)o来啊，快活啊!',
    avatar: 'mm',
    meta: guest,
    pageSize: '10' || 10,
    visitor: false,
    lang: 'zh-cn' || 'zh-cn'
  });
</script>




  


  




  

  

  

  

  

  

  

  

  

  

  

  

  

  

</body>
</html>
